/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						 abstract_combat_creature.h

	$Header: /heroes4/abstract_combat_creature.h $

	$NoKeywords: $

 ************************************************************************/

#if !defined( ABSTRACT_COMBAT_CREATURE_H_INCLUDED )
#define ABSTRACT_COMBAT_CREATURE_H_INCLUDED

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <map>
#include "abstract_creature.h"
#include "abstract_target.h"
#include "creature_stack_ptr.h"
#include "sized_int_types.h"
#include "spell.h"

class t_artifact_list;
class t_combat_action_message;
class t_creature_array;
class t_player;

enum t_spell_source
{
	k_spell_source_spell,
	k_spell_source_permanent,
	k_spell_source_artifact,

	k_spell_source_count
};

// ------------------------------------------------------------------------------
// artifact spell immunity information
// ------------------------------------------------------------------------------
struct t_artifact_spell_immunity
{
	t_spell		spell;
	std::string artifact_name;
};

typedef std::vector<t_artifact_spell_immunity>		 t_spell_immunity_array;
typedef std::map<t_spell, t_artifact_spell_immunity> t_spell_immunity_map;

// ----------------------------------------------------------------
// base class which defines common elements of simulated and normal
// combat creatures
// ----------------------------------------------------------------
class t_abstract_combat_creature : virtual public t_abstract_target, public t_abstract_creature
{
public:
	t_abstract_combat_creature( t_creature_stack* creature, int slot, 
		                        bool defender, t_player const* owner );

	void						add_immunity( t_artifact_spell_immunity const& immunity );
	virtual bool				belongs_to( bool defender ) const;
	bool						belongs_to_defender() const;
	virtual bool				can_cast( t_spell spell ) const;
	bool						can_remove( t_spell spell ) const;
	virtual bool				controlled_by( bool defender ) const;
	virtual t_town_type         get_alignment() const;
	virtual t_artifact const&	get_artifact( t_artifact_slot slot ) const;
	virtual int					get_backpack_count() const;
	virtual t_artifact const&	get_backpack_slot( int slot ) const;
	virtual int					get_combat_movement() const;
	virtual t_hero const*		get_const_hero() const;
	virtual bool				get_controller() const;
	t_creature_stack*			get_creature_stack() const;
	virtual t_creature_type     get_creature_type() const;
	virtual int					get_damage_high() const;
	virtual int					get_damage_low() const;
	virtual float				get_defense_basic( bool ranged ) const;
	virtual float				get_defense_bonus( bool ranged ) const;
	virtual	float				get_defense_reduction( bool ranged ) const;
	int							get_effect_power( t_spell spell ) const;
	virtual int                 get_experience_value( int number = -1 ) const;
	virtual t_abstract_grail_data_source const& get_grail_data() const = 0;
	virtual int					get_hit_points() const;
	int							get_leadership_luck_bonus() const;
	int							get_leadership_morale_bonus() const;
	virtual int                 get_luck() const;
	virtual int					get_magic_resistance( t_spell spell ) const;
	virtual int			        get_maximum_spell_points() const;
	virtual std::string			get_name( bool include_article = false, 
										  int number = -1 ) const;
	virtual int					get_number() const;
	virtual float				get_offense( bool ranged ) const;
	int							get_original_number() const;
	int							get_original_slot() const;
	int							get_permanent_deaths() const;
	virtual t_bitmap_layer_ptr	get_portrait( int height = 52, bool force_awake_portrait = false ) const;
	int							get_salvageable_bodies() const;
	virtual int					get_speed() const;
	virtual int                 get_spell_cost( t_spell spell ) const;
	virtual int					get_spell_points() const;
	int				            get_spell_power( t_spell spell, int number = -1 ) const;
	virtual int                 get_spell_power( t_spell spell, t_abstract_grail_data_source const & grail_data, int number = -1 ) const;
	virtual int					get_shots() const;
	virtual t_skill_mastery		get_skill( t_skill_type skill ) const;
	virtual bool                has_ability( t_creature_ability ability ) const;
	bool						has_artifact_immunity( t_spell	    spell, 
													   std::string* artifact_name = 0 ) const;
	bool						has_moved() const;
	bool						has_retaliated() const;
	virtual bool				is_active( t_spell spell ) const;
	bool	                    is_friendly( t_abstract_target const& creature ) const;
	bool	                    is_hostile( t_abstract_target const& creature ) const;
	bool						is_summoned() const;
	virtual bool                knows_spell( t_spell spell ) const;
	int						    modify_spell_damage( t_abstract_combat_creature const* caster,
													 int damage, t_spell spell ) const;
	void						record_losses( t_creature_array* armies ) const;
	void						redistribute_artifacts( t_creature_array** armies, t_artifact_list & booty );
	virtual t_artifact			remove_backpack( int slot );
	void						set_moved( bool arg );
	void						set_retaliated( bool arg );
	virtual void				set_spell( t_spell spell, 
										   t_combat_action_message const & message, 
										   int power = 0,
										   t_spell_source = k_spell_source_spell ) = 0;
	void						set_spell_points( int value );
	void						update_original_army( t_creature_array** armies );

protected:
	t_abstract_combat_creature();

	virtual void				do_update_original_army( t_creature_array** armies );

	bool read( std::streambuf& stream );
	bool write( std::streambuf& stream ) const;

	struct t_spell_effect
	{
		bool	active;
		t_int8	duration;
		int		power;
		bool    source[k_spell_source_count];

		t_spell_effect();
	};

	bool                    m_belongs_to_defender;
	t_creature_stack_ptr	m_creature_stack;
	bool                    m_has_moved;
	bool					m_has_retaliated;
	int						m_magic_resistance;
	int                     m_number;
	int                     m_original_slot;
	int                     m_permanent_deaths;
	int                     m_shots;
	t_spell_immunity_map	m_spell_immunities;
	int                     m_spell_points;
	t_spell_effect			m_spells[k_spell_count];
	t_spell_immunity_map	m_temporary_spell_immunities;
};

// ----------------------------------------------------------------
// inlines for abstract_combat_creature
// ----------------------------------------------------------------
inline bool t_abstract_combat_creature::belongs_to_defender() const
{
	return m_belongs_to_defender;
}

inline bool t_abstract_combat_creature::can_remove( t_spell spell ) const
{
	return !m_spells[spell].source[k_spell_source_permanent]
		&& !m_spells[spell].source[k_spell_source_artifact];
}

inline int t_abstract_combat_creature::get_effect_power( t_spell spell ) const
{
	return m_spells[spell].power;
}

inline int t_abstract_combat_creature::get_original_slot() const
{
	return m_original_slot;
}

inline int t_abstract_combat_creature::get_permanent_deaths() const
{
	return m_permanent_deaths;
}

inline int t_abstract_combat_creature::get_salvageable_bodies() const
{
	int result = get_original_number() - get_number() - m_permanent_deaths;

	if (result < 0)
		return 0;
	return result;
}

inline bool t_abstract_combat_creature::has_moved() const
{
	return m_has_moved;
}

inline bool t_abstract_combat_creature::has_retaliated() const
{
	return m_has_retaliated;
}

inline bool t_abstract_combat_creature::is_active( t_spell spell ) const
{
	return m_spells[spell].active;
}

inline bool t_abstract_combat_creature::is_summoned() const
{
	return m_original_slot < 0;
}

inline void t_abstract_combat_creature::set_moved( bool arg )
{
	m_has_moved = arg;
}

inline void t_abstract_combat_creature::set_retaliated( bool arg )
{
	m_has_retaliated = arg;
}

inline void t_abstract_combat_creature::set_spell_points( int value )
{
	m_spell_points = value;
}


#endif // ABSTRACT_COMBAT_CREATURE_H_INCLUDED